package com.learning.spring.aop.aspectj.annotation.advance;

import com.learning.spring.aop.aspectj.User;
import com.learning.spring.aop.aspectj.LogEntity;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

/**
 * ClassName: AdvanceAspect
 * Description: 进阶功能
 * Date: 2019/5/6 14:50 【需求编号】
 *
 * @author Sam Sho
 * @version V1.0.0
 */
@Aspect
public class AdvanceAspect {

    /**
     * 与运算。也支持 或运算（||）、非与运算（! &&）
     */
    @Before("within(com.learning.spring.aop.aspectj.*)" + "&& execution(* add(..))")
    public void before() {
        System.out.println("Hello @Before 复合运算");
    }


    /**
     * 命名切点
     */
    @Pointcut("execution(* update(..))")
    public void pointcut() {

    }

    @AfterReturning("pointcut()")
    public void after() {
        System.out.println("Hello @AfterReturning  @Pointcut 命名切点");
    }

    @Before("execution(* add(..))")
    public void joinPoint(JoinPoint joinPoint) {

        // 获取连接点方法运行时的入参列表
        Object[] args = joinPoint.getArgs();


        // 获取连接点的方法签名对象
        Signature signature = joinPoint.getSignature();

        // 获取连接点所在的目标对象
        Object target = joinPoint.getTarget();

        // 获取代理对象本身
        Object aThis = joinPoint.getThis();
    }

    /**
     * 访问连接点信息：JoinPoint
     */
    @Around("execution(* add(..))")
    public void proceedingJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable {

        // 获取连接点方法运行时的入参列表
        Object[] args = joinPoint.getArgs();


        // 获取连接点的方法签名对象
        Signature signature = joinPoint.getSignature();

        // 获取连接点所在的目标对象
        Object target = joinPoint.getTarget();

        // 获取代理对象本身
        Object aThis = joinPoint.getThis();

        // 通过反射执行目标对象的连接点处方法
        joinPoint.proceed();

        // 执行目标对象的连接点处方法，使用新的参数
        args[0] = "Eason";
        joinPoint.proceed(args);
    }

    /**
     * 绑定连接点方法入参。
     * <p>
     * 匹配 AopService 类中 方法入参为User 的方法
     * args(参数名)：
     * - 连接点匹配规则：连接点方法的入参是 User 类型
     * - 连接点方法入参和增强方法入参绑定
     *
     * @param user
     */
    @Before("target(com.learning.spring.aop.aspectj.AopService)" + "&& args(user)")
    public void args(User user) {
        System.out.println("Hello @Before args 绑定连接点方法入参");
        System.out.println(user);
    }

    /**
     * 绑定类注解对象
     *
     * @param logEntity
     */
    @Before("@within(logEntity)")
    public void annotation(LogEntity logEntity) {
        System.out.println("Hello @within annotation args 绑定类注解对象");
        System.out.println(logEntity);
    }

    /**
     * 绑定返回值
     *
     * @param result
     */
    @AfterReturning(value = "execution(* execute(..))", returning = "result")
    public void afterReturningValue(String result) {
        System.out.println("Hello @AfterReturning returning value 绑定返回值");
        System.out.println(result);
    }

    /**
     * 绑定异常
     *
     * @param ex
     */
    @AfterThrowing(value = "execution(* exception(..))", throwing = "ex")
    public void afterThrowing(Exception ex) {
        System.out.println("Hello @AfterReturning returning value 绑定异常");

        System.out.println(ex);
    }


}
